/*
 * PMemoryPool.cpp
 *
 *  Created on: Sep 6, 2013
 *      Author: yuliang
 */

#include "PMemoryPool.h"
#include "PException.h"
#include <string.h>

// Error Message
#define MEMPOOL_MEMORY_LOST "P_MP: Some Memory Leak ."
#define MEMPOOL_NEW_MEMORY_ERR "P_MP: New Memory Failed ."

#ifdef __UNITTEST
// Trace Message
#define MEMPOOL_NEW_MEMORY "P_MP : New Memory, Size : %d .\n"
#define MEMPOOL_DELETE_MEMORY "P_MP : Delete Memory, Size : %d .\n"
#define MEMPOOL_PUSH_MEMORY "P_MP : Push Memory, Size : %d .\n"
#define MEMPOOL_POP_MEMORY "P_MP : Pop Memory, Size : %d .\n"
#endif

CPMemoryPool::CPMemoryPool()
	: m_init(false) {
	// TODO Auto-generated constructor stub
	m_index[0] = S_1;
	m_index[1] = S_2;
	m_index[2] = S_3;
	m_index[3] = S_4;
	m_index[4] = S_5;
	memset(m_onesize, 0, PMEMORYPOOL_MODEL * sizeof(uint32_t));
	memset(m_poolsize, 0, PMEMORYPOOL_MODEL * sizeof(uint32_t));
	memset(m_curidlemem, 0, PMEMORYPOOL_MODEL * sizeof(Memory *));
}

CPMemoryPool::~CPMemoryPool() {
	// TODO Auto-generated destructor stub
	if (AllMemoryIdle()) {
		register uint32_t index = 0;
		while (index != PMEMORYPOOL_MODEL) {
			Memory *curtemp = m_curidlemem[index];
			Memory *nexttemp = 0;
			while (curtemp) {
				nexttemp =  curtemp->nextidle;
				delete []curtemp->m_mem;
				delete curtemp;
				curtemp = nexttemp;
#ifdef __UNITTEST
				printf(MEMPOOL_DELETE_MEMORY, m_onesize[index]);
#endif
			}
			++index;
		}
	} else
		throw USRERROR(MEMPOOL_MEMORY_LOST);
}

// 初始化, onesize为块内存大小,poolsize为块内存数量
bool CPMemoryPool::Init(uint32_t maxsize, uint32_t poolsize) {
	if (m_init)
		return true;

	{
		register uint32_t index = 0;
		while (index != PMEMORYPOOL_MODEL) {
			if (index == PMEMORYPOOL_MODEL - 1)
				m_onesize[index] = maxsize;
			else
				m_onesize[index] = (maxsize / PMEMORYPOOL_MODEL) * (index + 1);
			++index;
		}
	}
	m_init = true;

	while (poolsize) {
		register uint32_t index = 0;
		while (index != PMEMORYPOOL_MODEL) {
			if (!createOneMem(m_index[index])) {
				m_poolsize[m_index[index]] -= poolsize;
				throw USRERROR(MEMPOOL_NEW_MEMORY_ERR);
				return false;
			}
			++index;
		}
		--poolsize;
	}

	return true;
}

// 判断是否所有内存块都已闲置(只有全部闲置才可以释放内存池)
bool CPMemoryPool::AllMemoryIdle() const {
	if (!m_init)
		return true;
	register uint32_t index = 0;
	while (index != PMEMORYPOOL_MODEL) {
		register uint32_t size = 0;
		Memory *temp = m_curidlemem[m_index[index]];
		while(temp) {
			++size;
			temp = temp->nextidle;
		}
		if (size != m_poolsize[m_index[index]])
			return false;
		++index;
	}

	return true;
}

char *CPMemoryPool::PopMem(uint32_t len) {
	if (!m_init)
		return NULL;
	if (!len || len > m_onesize[m_index[PMEMORYPOOL_MODEL - 1]])
		return NULL;

	MemorySize t_size = memSize(len);
	// 无闲置的内存
	if (!m_curidlemem[t_size]) {
		// 创建一块新内存
		if (!createOneMem(t_size))
			return NULL;
	}
	// 记录当前的memory stack
	char *curmem = m_curidlemem[t_size]->m_mem;
	Memory * mem = m_curidlemem[t_size]->nextidle;
	// 释放保存内存数据对象
	delete m_curidlemem[t_size];
	// 修改当前闲置内存
	m_curidlemem[t_size] = mem;

#ifdef __UNITTEST
	printf(MEMPOOL_POP_MEMORY, m_onesize[t_size]);
#endif
	// 返回有效数据的内存块
	return curmem;
}

// 将外部数据放到闲置的内存块上
const char * CPMemoryPool::PopMem(const char *buf, uint32_t len) {
	if (!m_init)
		return NULL;
	if (!len || len > m_onesize[m_index[PMEMORYPOOL_MODEL - 1]])
		return NULL;

	MemorySize t_size = memSize(len);
	// 无闲置的内存
	if (!m_curidlemem[t_size]) {
		// 创建一块新内存
		if (!createOneMem(t_size))
			return NULL;
	}
	// 记录当前的memory stack
	const char *curmem = m_curidlemem[t_size]->m_mem;
	Memory * mem = m_curidlemem[t_size]->nextidle;
	memcpy(m_curidlemem[t_size]->m_mem, buf, len);
	// 释放保存内存数据对象
	delete m_curidlemem[t_size];
	// 修改当前闲置内存
	m_curidlemem[t_size] = mem;

#ifdef __UNITTEST
	printf(MEMPOOL_POP_MEMORY, m_onesize[t_size]);
#endif
	// 返回有效数据的内存块
	return curmem;
}

// 将用完的内存块置为闲置
void CPMemoryPool::PushMem(char *buf, uint32_t len) {
	if (!m_init)
		return;
	if (!len || len > m_onesize[m_index[PMEMORYPOOL_MODEL - 1]]) {
		delete []buf;
		return;
	}

	// 创建一个保存内存数据对象
	Memory *one = new Memory;
	if (!one) {
		delete []buf;
		return;
	}

	// 保存内存地址
	one->m_mem = buf;
	// 添加闲置内存
	pushPool(one, memSize(len));

#ifdef __UNITTEST
	printf(MEMPOOL_PUSH_MEMORY, m_onesize[memSize(len)]);
#endif
}

// 创建一个内存块及保存内存块对象
bool CPMemoryPool::createOneMem(MemorySize i) {
	// 创建一个保存内存数据对象
	Memory *one = new Memory;
	if (!one)
		return false;
	// 创建一块内存
	one->m_mem = new char[m_onesize[i]];
	if (!one->m_mem) {
		delete one;
		return false;
	}

	// 添加闲置内存
	pushPool(one, i);
	m_poolsize[i] += 1;

#ifdef __UNITTEST
	printf(MEMPOOL_NEW_MEMORY, m_onesize[i]);
#endif
	return true;
}

// 添加闲置内存块
void CPMemoryPool::pushPool(Memory *one, MemorySize i) {
	if (!m_curidlemem[i]) {
		m_curidlemem[i] = one;
		m_curidlemem[i]->nextidle = 0;
	} else {
		one->nextidle = m_curidlemem[i]->nextidle;
		m_curidlemem[i]->nextidle = one;
	}
}

CPMemoryPool::MemorySize CPMemoryPool::memSize(uint32_t len) {
	register uint32_t frontsize = 0;
	register uint32_t index = 0;
	MemorySize size = S_1;
	while (index != PMEMORYPOOL_MODEL) {
		if (len > frontsize && len <= m_onesize[index]) {
			size = m_index[index];
			break;
		}
		frontsize = m_onesize[index];
		++index;
	}
	return size;
}

